import 'package:path/path.dart';
import 'package:xindong/common/xindong_methods.dart';
import 'package:sqflite/sqflite.dart';

class XinDongDatabaseSingleton {
  late Database database;

  // 表名
  static const String tableNameAccount = "account";
  static const String tableNameNearby = "nearby";
  static const String tableNameQuality = "quality";
  static const String tableNameTrends = "moments";

  // 其他表
  static const String tableNameAccost = "accost"; // 搭讪

  // 表列字段
  final String kKeyId = "id";
  final String kKeyData = "data";
  final String kKeyUpdateAt = "update_at";

  // 公共表
  final commonTables = [tableNameAccount, tableNameNearby, tableNameTrends, tableNameQuality];

  // 初始化创建表
  Future<void> setup() async {
    database = await _open();
    for (var element in commonTables) {
      // 表设计统一为id整型字段、data字符串字段
      // id 主键
      // data 存放json字符串
      // update_at 存放更新时间戳（13位毫秒）
      await database.execute('CREATE TABLE IF NOT EXISTS $element (id INTEGER PRIMARY KEY, $kKeyData TEXT, $kKeyUpdateAt INTEGER DEFAULT 0)');
      mDebugPrint("数据库创建表 $element");
      // var res = await database.rawUpdate('ALTER TABLE $element ADD COLUMN $kKeyUpdateAt INTEGER');
      // print(res);
    }
    await createTableSayHello();
    return Future.value();
  }

  // 数据表清除所有数据
  htmy_clear() async {
    for (var element in commonTables) {
      if (element == tableNameAccount) {
        continue;
      }
      await deleteAll(tableName: element);
    }
    mDebugPrint("数据表清除所有数据，除了$tableNameAccount表");
  }

  test() async {
    // 表结构 id data
    // await insert(tableName: "nearby", jsonData: "jsonDataaaaaaaaaa");
    // await insert(tableName: "nearby", jsonData: "jsonDataaaaaaaaaabbbbbbcccc", primaryId: 100);
    // query(tableName: "nearby", primaryId: 100);
    // queryAll(tableName: "nearby");
    // // await deleteAll(tableName: "nearby");
    // await update(tableName: "nearby", jsonData: "jsonData", primaryId: 10);
    // await insertMultiple(tableName: "nearby", jsonList: ["jsonData1", "jsonData2", "jsonData3"], primaryIds: [101, 102, 103]);
    // queryAll(tableName: "nearby");

    await htmy_insertSayHello(userId: "111", targetUid: "222", updateAt: 333);
    queryAll(tableName: tableNameAccost);
  }

  /// 打开数据库
  Future _open() async {
    return await openDatabase(
      // 设置数据库的路径。注意：使用 `path` 包中的 `join` 方法是
      // 确保在多平台上路径都正确的最佳实践。
      join(await getDatabasesPath(), 'htmy_database.db'),
      // 设置版本。它将执行 onCreate 方法，同时提供数据库升级和降级的路径。
      version: 2,
      // 当数据库第一次被创建的时候，创建一个或多个数据表，用以存储狗狗们的数据。
      onCreate: (Database db, int version) async {
        mDebugPrint("数据库创建");
      },
    );
  }

  /// 关闭
  Future close() async => database.close();

  /// 插入单条数据到指定数据表
  ///
  /// tableName 表名，必填
  /// jsonData 数据内容，所有数据都转换成json字符串数据，必填
  /// primaryId 主键ID，默认null，自增；填写则指定ID，有重复的会replace替换原有内容
  /// return 返回插入数据的ID
  Future<int> insert({required String tableName, required String jsonData, int? primaryId}) async {
    try {
      final updateAt = DateTime.now().millisecondsSinceEpoch;
      final result = await database.insert(
        tableName,
        {"id": primaryId, kKeyData: jsonData, kKeyUpdateAt: updateAt},
        conflictAlgorithm: ConflictAlgorithm.replace,
      );
      mDebugPrint("数据库插入数据 - 表：$tableName，ID：$result");
      return result;
    } catch (error) {
      mCatchPrint(error);
      return 0;
    }
  }

  /// 插入单条数据到指定数据表
  ///
  /// tableName 表名，必填
  /// jsonList 数据内容，所有数据都转换成json字符串数据数组，必填
  /// primaryIds 主键IDs，默认null
  /// return 返回
  Future insertMultiple({required String tableName, required List<String> jsonList, List<int>? primaryIds}) async {
    // 事务
    return await database.transaction((Transaction txn) async {
      final updateAt = DateTime.now().millisecondsSinceEpoch;
      // 批处理
      var batch = txn.batch();
      for (int i = 0; i < jsonList.length; i++) {
        batch.insert(
          tableName,
          {"id": primaryIds?[i], kKeyData: jsonList[i], kKeyUpdateAt: updateAt},
          conflictAlgorithm: ConflictAlgorithm.replace,
        );
      }
      // commit but the actual commit will happen when the transaction is committed
      // however the data is available in this transaction
      final result = await batch.commit(continueOnError: true);
      mDebugPrint("数据库批量插入数据 - 表：$tableName，结果：$result");
    });
  }

  /// 删除指定数据表单条数据
  ///
  /// tableName 表名，必填
  /// primaryId 主键ID，必填
  /// return 返回成功失败
  Future<bool> delete({required String tableName, required int primaryId}) async {
    try {
      // 删除成功的数量
      final result = await database.delete(tableName, where: 'id = ?', whereArgs: [primaryId]);
      mDebugPrint("数据库删除数据 - 表：$tableName，结果：$result条记录");
      return result > 0;
    } catch (error) {
      mCatchPrint(error);
      return false;
    }
  }

  /// 删除指定数据表所有数据
  ///
  /// tableName 表名，必填
  /// return 返回成功失败
  Future<bool> deleteAll({required String tableName}) async {
    try {
      // 删除成功的数量
      final result = await database.delete(tableName);
      mDebugPrint("数据库删除数据 - 表：$tableName，结果：$result条记录");
      return result > 0;
    } catch (error) {
      mCatchPrint(error);
      return false;
    }
  }

  /// 更新指定ID数据到指定数据表
  ///
  /// tableName 表名，必填
  /// jsonData 数据内容，所有数据都转换成json字符串数据，必填
  /// primaryId 主键ID，必填
  /// return 返回成功失败
  Future<bool> update({required String tableName, required String jsonData, required int primaryId}) async {
    try {
      final updateAt = DateTime.now().millisecondsSinceEpoch;
      // 更新成功的数量
      final result = await database.update(
        tableName,
        {"id": primaryId, kKeyData: jsonData, kKeyUpdateAt: updateAt},
        where: 'id = ?',
        whereArgs: [primaryId],
      );
      mDebugPrint("数据库更新数据 - 表：$tableName，结果：$result条记录");
      return result > 0;
    } catch (error) {
      mCatchPrint(error);
      return false;
    }
  }

  /// 查询指定数据表指定ID数据
  ///
  /// tableName 表名，必填
  /// primaryId 主键ID，必填
  /// return 返回数据
  Future<List> query({required String tableName, required int primaryId}) async {
    try {
      List<Map<String, dynamic>> result = await database.query(
        tableName,
        where: 'id = ?',
        whereArgs: [primaryId],
      );
      mDebugPrint("数据库查询数据 - 表：$tableName，结果：$result");
      return result;
    } catch (error) {
      mCatchPrint(error);
      return [];
    }
  }

  /// 查询指定数据表所有数据
  ///
  /// tableName 表名，必填
  /// orderBy 排序，选填
  /// return 返回数据数组
  Future<List> queryAll({required String tableName, String? orderBy}) async {
    try {
      List<Map<String, dynamic>> result = await database.query(tableName, orderBy: orderBy);
      mDebugPrint("数据库查询数据 - 表：$tableName，结果：$result");
      // mDebugPrint("数据库查询数据 - 表：$tableName，结果：${result.length}");
      return result;
    } catch (error) {
      mCatchPrint(error);
      return [];
    }
  }

  /// ======== 单例
  // 工厂方法构造函数
  factory XinDongDatabaseSingleton() => _getInstance();

  // instance的getter方法，singletonManager.instance获取对象
  static XinDongDatabaseSingleton get instance => _getInstance();

  // 静态变量_instance，存储唯一对象
  static XinDongDatabaseSingleton? _instance;

  // 获取对象
  static XinDongDatabaseSingleton _getInstance() {
    _instance ??= XinDongDatabaseSingleton._internal();
    return _instance!;
  }

  // 私有的自定义命名式构造方法，通过它实现一个类;
  // 子类不能继承internal
  // 不是关键字，可定义其他名字
  XinDongDatabaseSingleton._internal() {
    // 初始化(设置一些默认的)...
  }
}

/// 扩展用户存储
extension XinDongAccountDatabase on XinDongDatabaseSingleton {
  // // 插入账户
  // void htmy_insertAccount(XinDongAccount account) {
  //   // 异步，不阻碍主线程界面显示
  //   Future.delayed(Duration.zero).whenComplete(() async {
  //     try {
  //       // 由于primaryId是uid，所以不能默认
  //       final map = {
  //         "uid": account.user.uid,
  //         "nick": account.user.nick,
  //         "avatar": account.user.avatar ?? "",
  //         "mobile": account.user.mobile ?? "",
  //         "token": account.token,
  //       };
  //       final primaryId = account.user.uid;
  //       final jsonData = json.encode(map);
  //
  //       await insert(tableName: XinDongDatabaseManager.tableNameAccount, jsonData: jsonData, primaryId: primaryId);
  //       // 测试查询
  //       // queryAll(tableName: XinDongDatabaseManager.tableNameAccount);
  //     } catch (error) {
  //       mCatchPrint(error);
  //     }
  //   });
  // }
  //
  // // 查询账户列表数据
  // Future<List> htmy_queryAccounts() async {
  //   try {
  //     final result = await queryAll(tableName: XinDongDatabaseManager.tableNameAccount, orderBy: "$kKeyUpdateAt DESC");
  //     return result.map((e) => json.decode(e[kKeyData])).toList();
  //   } catch (error) {
  //     mCatchPrint(error);
  //     return [];
  //   }
  // }
}

/// 扩展模型存储
extension XinDongClassDatabase on XinDongDatabaseSingleton {
  // 插入附近数据
  // void htmy_insertDataNearby(List<XinDongUserClass> dataList) {
  //   if (dataList.isEmpty) {
  //     return;
  //   }
  //   // 异步，不阻碍主线程界面显示
  //   Future.delayed(Duration.zero).whenComplete(() async {
  //     try {
  //       // 由于primaryId是uid，所以不能默认
  //       final jsonList = dataList.map((e) => json.encode(e)).toList();
  //       final primaryIds = dataList.map((e) => e.uid).toList();
  //
  //       // 清空数据
  //       await deleteAll(tableName: XinDongDatabaseManager.tableNameNearby);
  //
  //       // 数据库操作
  //       await insertMultiple(tableName: XinDongDatabaseManager.tableNameNearby, jsonList: jsonList, primaryIds: primaryIds);
  //       // 测试查询
  //       // queryAll(tableName: XinDongDatabaseManager.tableNameNearby);
  //     } catch (error) {
  //       mCatchPrint(error);
  //     }
  //   });
  // }
  //
  // // 查询附近数据
  // Future<List<XinDongUserClass>> htmy_queryDataNearby() async {
  //   try {
  //     final result = await queryAll(tableName: XinDongDatabaseManager.tableNameNearby);
  //     return result.map((e) {
  //       final data = json.decode(e[kKeyData]);
  //       return XinDongUserClass.fromJson(data);
  //     }).toList();
  //   } catch (error) {
  //     mCatchPrint(error);
  //     return [];
  //   }
  // }
  //
  // // 插入附近数据
  // void htmy_insertDataAnchor(List<XinDongUserClass> dataList) {
  //   if (dataList.isEmpty) {
  //     return;
  //   }
  //   // 异步，不阻碍主线程界面显示
  //   Future.delayed(Duration.zero).whenComplete(() async {
  //     try {
  //       // 由于primaryId是uid，所以不能默认
  //       final jsonList = dataList.map((e) => json.encode(e)).toList();
  //       final primaryIds = dataList.map((e) => e.uid).toList();
  //
  //       // 清空数据
  //       await deleteAll(tableName: XinDongDatabaseManager.tableNameAnchor);
  //
  //       // 数据库操作
  //       await insertMultiple(tableName: XinDongDatabaseManager.tableNameAnchor, jsonList: jsonList, primaryIds: primaryIds);
  //       // 测试查询
  //       // queryAll(tableName: XinDongDatabaseManager.tableNameNearby);
  //     } catch (error) {
  //       mCatchPrint(error);
  //     }
  //   });
  // }
  //
  // // 查询附近数据
  // Future<List<XinDongUserClass>> htmy_queryDataAnchor() async {
  //   try {
  //     final result = await queryAll(tableName: XinDongDatabaseManager.tableNameAnchor);
  //     return result.map((e) {
  //       final data = json.decode(e[kKeyData]);
  //       return XinDongUserClass.fromJson(data);
  //     }).toList();
  //   } catch (error) {
  //     mCatchPrint(error);
  //     return [];
  //   }
  // }
  //
  // // 插入广播数据
  // void htmy_insertDataTrends(List<XinDongTrendClass> dataList) {
  //   if (dataList.isEmpty) {
  //     return;
  //   }
  //   // 异步，不阻碍主线程界面显示
  //   Future.delayed(Duration.zero).whenComplete(() async {
  //     try {
  //       // 由于primaryId是uid，所以不能默认
  //       final jsonList = dataList.map((e) => json.encode(e)).toList();
  //       final primaryIds = dataList.map((e) => e.did).toList();
  //
  //       // 清空数据
  //       await deleteAll(tableName: XinDongDatabaseManager.tableNameTrends);
  //
  //       // 数据库操作
  //       await insertMultiple(tableName: XinDongDatabaseManager.tableNameTrends, jsonList: jsonList, primaryIds: primaryIds);
  //       // 测试查询
  //       // queryAll(tableName: XinDongDatabaseManager.tableNameNearby);
  //     } catch (error) {
  //       mCatchPrint(error);
  //     }
  //   });
  // }
  //
  // // 查询广播数据
  // Future<List<XinDongTrendClass>> htmy_queryDataTrends() async {
  //   try {
  //     final result = await queryAll(tableName: XinDongDatabaseManager.tableNameTrends);
  //     return result.map((e) {
  //       final data = json.decode(e[kKeyData]);
  //       return XinDongTrendClass.fromJson(data);
  //     }).toList();
  //   } catch (error) {
  //     mCatchPrint(error);
  //     return [];
  //   }
  // }
}

/// 扩展打招呼存储
extension XinDongSayHelloDatabase on XinDongDatabaseSingleton {
  // 其他不同字段的表
  static const String kKeyUserId = "user_id";
  static const String kKeyTargetUid = "target_uid";

  // 创建表 id user_id target_uid update_at
  // IDENTITY(1,1) 第一个自增从1开始，第二个每次自增量为1
  Future<void> createTableSayHello() async {
    // await database.execute("DROP TABLE IF EXISTS ${XinDongDatabaseManager.tableNameSayHello}");
    // mDebugPrint("数据库删除表 ${XinDongDatabaseManager.tableNameSayHello}");
    await database.execute('CREATE TABLE IF NOT EXISTS ${XinDongDatabaseSingleton.tableNameAccost} ('
        'id INTEGER PRIMARY KEY AUTOINCREMENT, '
        '$kKeyUserId TEXT, '
        '$kKeyTargetUid TEXT, '
        '$kKeyUpdateAt INTEGER DEFAULT 0'
        ')');
    mDebugPrint("数据库创建表 ${XinDongDatabaseSingleton.tableNameAccost}");
    return Future.value();
  }

  // 重置自增ID
  htmy_resetSayHelloAutoIncrement() {
    const tableName = XinDongDatabaseSingleton.tableNameAccost;
    database.transaction((Transaction txn) async {
      // 使用rawQuery查询数据库
      int? count = Sqflite.firstIntValue(await txn.rawQuery("SELECT COUNT(*) FROM $tableName"));
      if (count == 0) {
        // 需要表数据全部清空才有效
        // 重置为0，下一次生成的将会是1，指定表名
        final result = await txn.rawUpdate('UPDATE sqlite_sequence SET seq = 0 WHERE name = ?', [tableName]);
        mDebugPrint("数据库重置自增ID $tableName，结果：$result");
      } else {
        mDebugPrint("数据库重置自增ID $tableName，结果：$count 数据未清空，不能重置");
      }
    });
  }

  // 删除过期数据
  Future<void> htmy_deleteSayHelloExpired({required int expiredTime}) async {
    const tableName = XinDongDatabaseSingleton.tableNameAccost;
    final result = await database.rawDelete('DELETE FROM $tableName WHERE $kKeyUpdateAt < ?', [expiredTime]);
    mDebugPrint("数据库删除数据 - 表：$tableName，结果：$result条记录");
    // 清空之后看看能不能重置自增ID
    htmy_resetSayHelloAutoIncrement();
    return Future.value();
  }

  // 插入数据，有数据则更新优先
  htmy_insertSayHello({required String userId, required String targetUid, required int updateAt}) async {
    try {
      const tableName = XinDongDatabaseSingleton.tableNameAccost;
      final count = await database.update(
        tableName,
        {kKeyUserId: userId, kKeyTargetUid: targetUid, kKeyUpdateAt: updateAt},
        where: "$kKeyUserId = ? AND $kKeyTargetUid = ?",
        whereArgs: [userId, targetUid],
      );
      if (count == 0) {
        final result = await database.insert(
          tableName,
          {kKeyUserId: userId, kKeyTargetUid: targetUid, kKeyUpdateAt: updateAt},
          conflictAlgorithm: ConflictAlgorithm.replace,
        );
        mDebugPrint("数据库插入数据 - 表：${XinDongDatabaseSingleton.tableNameAccost}，ID：$result");
        return result;
      } else {
        mDebugPrint("数据库更新数据 - 表：${XinDongDatabaseSingleton.tableNameAccost}，ID：$count");
        return count;
      }
    } catch (error) {
      mCatchPrint(error);
      return 0;
    }
  }

  // 插入数据，有数据则更新优先
  htmy_insertMultipleSayHello({required String userId, required List<String> targetIds, required int updateAt}) async {
    // 事务
    const tableName = XinDongDatabaseSingleton.tableNameAccost;
    return await database.transaction((Transaction txn) async {
      // 批处理
      var batch = txn.batch();
      targetIds.forEach((element) async {
        batch.insert(
          tableName,
          {kKeyUserId: userId, kKeyTargetUid: element, kKeyUpdateAt: updateAt},
          conflictAlgorithm: ConflictAlgorithm.replace,
        );
      });
      // commit but the actual commit will happen when the transaction is committed
      // however the data is available in this transaction
      final result = await batch.commit(continueOnError: true);
      mDebugPrint("数据库批量插入数据 - 表：$tableName，结果：$result");
    });
  }

  htmy_deleteSayHello() async {
    try {
      const tableName = XinDongDatabaseSingleton.tableNameAccost;
      final result = await database.delete(tableName);
      mDebugPrint("数据库删除数据 - 表：$tableName，结果：$result条记录");
      return result;
    } catch (error) {
      mCatchPrint(error);
      return 0;
    }
  }

  htmy_deleteSayHelloWithUserId({required int userId}) async {
    const tableName = XinDongDatabaseSingleton.tableNameAccost;
    final result = await database.delete(
      tableName,
      where: "$kKeyUserId = ?",
      whereArgs: [userId],
    );
    mDebugPrint("数据库删除数据 - 表：$tableName，结果：$result条记录");
  }

  // 删除 根据主键ID
  htmy_deleteSayHelloWithId(int id) async {
    final result = await database.delete(
      XinDongDatabaseSingleton.tableNameAccost,
      where: "id = ?",
      whereArgs: [id],
    );
    mDebugPrint("数据库删除数据 - 表：${XinDongDatabaseSingleton.tableNameAccost}，结果：$result条记录");
  }

  Future<List> htmy_querySayHello() async {
    return await queryAll(tableName: XinDongDatabaseSingleton.tableNameAccost);
  }

  Future<List> htmy_querySayHelloWithUserId(String userId) async {
    try {
      const tableName = XinDongDatabaseSingleton.tableNameAccost;
      List<Map<String, dynamic>> result = await database.query(
        tableName,
        orderBy: "$kKeyUpdateAt DESC",
        where: "$kKeyUserId = ?",
        whereArgs: [userId],
      );
      mDebugPrint("数据库查询数据 - 表：$tableName，结果：$result");
      // mDebugPrint("数据库查询数据 - 表：$tableName，结果：${result.length}");
      return result;
    } catch (error) {
      mCatchPrint(error);
      return [];
    }
  }
}
